package com.vhall.component.service.account.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.vhall.component.dao.account.AccountAdminsMapper;
import com.vhall.component.dao.account.AdminRoleMapper;
import com.vhall.component.dao.account.RoleMapper;
import com.vhall.component.entity.account.AdminsEntity;
import com.vhall.component.entity.account.RoleEntity;
import com.vhall.component.entity.account.dto.IndexDto;
import com.vhall.component.entity.account.vo.*;
import com.vhall.component.entity.export.dto.AdminExportCommonQueryCondition;
import com.vhall.component.framework.common.constant.CommonConstant;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.framework.common.utils.StringUtils;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.service.account.AdminInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xianglei
 * @date 2021/7/21 16:29
 */
@Service
@Slf4j
public class AdminInfoServiceImpl implements AdminInfoService {

    private static final String CREATED_AT = "created_at";

    private static final List<Integer> SUPER_ADMIN_LIST = Collections.singletonList(1);

    @Autowired
    private AccountAdminsMapper accountAdminsMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private AdminRoleMapper adminRoleMapper;

    /**
     * 获取管理员信息
     *
     * @param reqVo
     * @return
     */
    @Override
    public AdminGetInfoRspVo get(AdminGetInfoReqVo reqVo) {
        AdminsEntity adminsEntity = accountAdminsMapper.selectById(reqVo.getAdminId());
        if (adminsEntity == null) {
            throw new BusinessException(BizErrorCode.BIZ_INVALID_USER);
        }
        RoleEntity roleEntity = roleMapper.selectById(adminsEntity.getRoleId());
        AdminGetInfoRspVo rspVo = new AdminGetInfoRspVo();
        RoleRspVO roleRspVO = new RoleRspVO();
        BeanUtils.copyProperties(adminsEntity, rspVo);
        if (roleEntity == null) {
            rspVo.setRole(null);
            return rspVo;
        }
        BeanUtils.copyProperties(roleEntity, roleRspVO);
        rspVo.setRole(roleRspVO);
        return rspVo;
    }

    @Override
    public Boolean editPassword(AdmEditPasswordReqVO reqVO) {
        if (!Objects.equals(reqVO.getPassword(), reqVO.getConfirmPassword())) {
            throw new BusinessException(BizErrorCode.AUTH_PASSWORDS_DIFFER);
        }
        AdminsEntity adminsEntity = accountAdminsMapper.selectById(reqVO.getAdminId());
        if (adminsEntity == null) {
            throw new BusinessException(BizErrorCode.BIZ_ADMIN_EMPTY);
        }
        Digester sha256 = new Digester(DigestAlgorithm.SHA256);
        String md5PassWord = sha256.digestHex(reqVO.getPassword() + adminsEntity.getSalt());
        adminsEntity.setPassword(md5PassWord);

        int update = accountAdminsMapper.updateById(adminsEntity);
        if (update < 0) {
            throw new BusinessException(BizErrorCode.BIZ_EDIT_FAILED);
        }
        return true;

    }

    @Override
    public List<Integer> delete(AdmDeleteReqVO reqVO) {
        ArrayList<Integer> rspVO = new ArrayList<>();
        List<Integer> adminidList = StrUtil.splitTrim(reqVO.getAdminIds(), ",")
                .stream()
                .map(Integer::valueOf)
                .collect(Collectors.toList());

        for (Integer adminId : adminidList) {
            if (SUPER_ADMIN_LIST.contains(adminId)) {
                continue;
            }
            AdminsEntity adminsEntity = accountAdminsMapper.selectById(adminId);
            if (adminsEntity != null) {
                accountAdminsMapper.deleteById(adminsEntity);
                rspVO.add(adminId);
            }

        }
        return rspVO;
    }


    @Override
    public Boolean editStatus(AdmEditStatusReqVO reqVO) {
        AdminsEntity adminsEntity = accountAdminsMapper.selectById(reqVO.getAdminId());
        if (adminsEntity == null) {
            throw new BusinessException(BizErrorCode.BIZ_ADMIN_EMPTY);
        }
        adminsEntity.setStatus(reqVO.getStatus());
        int update = accountAdminsMapper.updateById(adminsEntity);
        if (update < 0) {
            throw new BusinessException(BizErrorCode.BIZ_EDIT_FAILED);
        }
        return true;

    }

    @Override
    public Boolean edit(AdmEditReqVO vo) {

        //管理员消息
        AdminsEntity adm = accountAdminsMapper.selectById(vo.getAdminId());
        if (adm == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ADMIN);
        }

        LambdaQueryWrapper<AdminsEntity> que = Wrappers.lambdaQuery();
        que.eq(AdminsEntity::getAdminName, vo.getAdminName());
        Integer count = accountAdminsMapper.selectCount(que);

        LambdaQueryWrapper<AdminsEntity> querynk = Wrappers.lambdaQuery();
        querynk.eq(AdminsEntity::getNickName, vo.getNickName());
        Integer countnk = accountAdminsMapper.selectCount(querynk);

        //登录已经存在名
        if (!vo.getAdminName().equals(adm.getAdminName()) && count > 0) {
            throw new BusinessException(BizErrorCode.BIZ_USER_NAME_EXIST);
        }

        //保存数据
        adm.setAdminName(vo.getAdminName());
        adm.setNickName(vo.getNickName());
        adm.setMobile(vo.getMobile());
        adm.setEmail(vo.getEmail());
        adm.setRoleId(vo.getRoleId());
        //验证密码
        if (StringUtils.isNotEmpty(vo.getPassword())) {
            if (!vo.getPassword().equals(vo.getConfirmPassword())) {
                throw new BusinessException(BizErrorCode.AUTH_PASSWORDS_DIFFER);
            }
            Digester sha256 = new Digester(DigestAlgorithm.SHA256);
            String pass = sha256.digestHex(vo.getPassword() + adm.getSalt());
            adm.setPassword(pass);
        }
        if (accountAdminsMapper.updateById(adm) < 0) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    private IndexDto getAdminsCount(String beginTime) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern(CommonConstant.DATETIME_FORMAT);
        LocalDateTime time = LocalDateTime.parse(beginTime, df);
        QueryWrapper<AdminsEntity> queryWrapper = new QueryWrapper<>();
        Integer total = accountAdminsMapper.selectCount(queryWrapper);
        queryWrapper.clear();
        Integer day = accountAdminsMapper.selectCount(queryWrapper.gt(CREATED_AT, time));
        queryWrapper.clear();
        Integer week = accountAdminsMapper.selectCount(queryWrapper.gt(CREATED_AT, time.minusWeeks(1L)));
        queryWrapper.clear();
        Integer month = accountAdminsMapper.selectCount(queryWrapper.gt(CREATED_AT, time.minusMonths(1L)));
        queryWrapper.clear();
        Integer year = accountAdminsMapper.selectCount(queryWrapper.gt(CREATED_AT, time.minusYears(1L)));
        IndexDto indexDto = new IndexDto();
        indexDto.setTotal(total);
        indexDto.setDay(day);
        indexDto.setWeek(week);
        indexDto.setMonth(month);
        indexDto.setYear(year);
        return indexDto;
    }

    @Override
    public AdminListRspVO list(AdminListReqVO reqVO) {
        AdminListRspVO rspVO = new AdminListRspVO();
        Integer page = reqVO.getPage();
        Integer pageSize = 10;

        Map<String, Object> where = new HashMap<>(8);
        where.put("keyword", reqVO.getKeyword());
        where.put("beginTime", reqVO.getBeginTime());
        where.put("endTime", reqVO.getEndTime());
        Integer total = adminRoleMapper.countAdminRoleList(where);
        createPageParams(rspVO, total, page, pageSize);
        if (total <= 0) {
            rspVO.setData(Collections.emptyList());
            return rspVO;
        }
        where.put("offset", (page - 1) * pageSize);
        where.put("limit", pageSize);
        List<AdminRoleListRspVO> adminRoleList = adminRoleMapper.adminRoleList(where);

        for (AdminRoleListRspVO vo : adminRoleList) {
            vo.setStatusStr(getStatusStr(vo.getStatus()));
        }
        rspVO.setData(adminRoleList);

        return rspVO;
    }

    /**
     * 构建status_str
     *
     * @param status
     * @return
     */
    private String getStatusStr(Integer status) {
        String statusStr;
        switch (status) {
            case 0:
                statusStr = "禁用";
                break;
            case 1:
                statusStr = "正常";
                break;
            default:
                statusStr = null;
        }

        return statusStr;


    }

    @Override
    public AdminAddRspVO add(AdminAddReqVO reqVO) {
        LambdaQueryWrapper<AdminsEntity> where = Wrappers.lambdaQuery();
        where.eq(AdminsEntity::getAdminName, reqVO.getAdminName());
        // 登录名已存在
        if (accountAdminsMapper.selectCount(where) > 0) {
            throw new BusinessException(BizErrorCode.BIZ_USER_NAME_EXIST);
        }
        // 两次密码是否一致
        if (!Objects.equals(reqVO.getPassword(), reqVO.getConfirmPassword())) {
            throw new BusinessException(BizErrorCode.AUTH_PASSWORDS_DIFFER);
        }
        String salt = RandomUtil.randomString(6);
        AdminsEntity adminsEntity = new AdminsEntity();
        adminsEntity.setAdminName(reqVO.getAdminName());
        adminsEntity.setNickName(RandomUtil.randomString(10));
        adminsEntity.setSalt(salt);
        Digester sha256 = new Digester(DigestAlgorithm.SHA256);
        String digestHex = sha256.digestHex(reqVO.getPassword() + salt);
        adminsEntity.setPassword(digestHex);

        adminsEntity.setMobile(reqVO.getMobile());
        adminsEntity.setEmail(reqVO.getEmail());
        adminsEntity.setRoleId(reqVO.getRoleId());
        adminsEntity.setStatus(1);
        adminsEntity.setCreatedAt(LocalDateTime.now());
        adminsEntity.setUpdatedAt(LocalDateTime.now());
        int insert = accountAdminsMapper.insert(adminsEntity);
        if (insert < 0) {
            throw new BusinessException(BizErrorCode.BIZ_CREATE_FAILED);
        }
        AdminAddRspVO rspVO = new AdminAddRspVO();
        BeanUtils.copyProperties(adminsEntity, rspVO);
        return rspVO;
    }

    @Override
    public Integer countAdminForAdminExport(AdminExportCommonQueryCondition condition) {
        QueryWrapper<Object> wrapper = new QueryWrapper<>();
        if (Objects.nonNull(condition)) {
            String createdAtColumn = "admins.created_at";
            // 开始日期、结束日期
            wrapper.ge(Objects.nonNull(condition.getStartTime()), createdAtColumn, condition.getStartTime());
            if (Objects.nonNull(condition.getEndTime())) {
                wrapper.lt(createdAtColumn, condition.getEndTime().plusDays(1));
            }
            String keyword = condition.getKeyword();
            // 模糊查询支持，账号、手机号、昵称
            wrapper.and(StringUtils.isNotEmpty(keyword),
                    w -> w.like("admins.admin_name", keyword).or().like("admins.mobile", keyword));
        }
        return accountAdminsMapper.countForAdmin(wrapper);
    }

    private void createPageParams(AdminListRspVO rspVO, Integer total, Integer currPage, Integer pageSize) {
        int offset = (currPage - 1) * pageSize;
        rspVO.setCurrentPage(currPage);
        rspVO.setPerPage(pageSize);
        rspVO.setTotal(total);
        rspVO.setPath("/");
        Integer lastPage = total % pageSize == 0 ? total / pageSize : (total / pageSize) + 1;
        rspVO.setLastPage(lastPage);
        Integer firstItem = offset + 1;
        rspVO.setFrom(firstItem);
        Integer lastItem = firstItem + total - 1;
        rspVO.setTo(lastItem);
        rspVO.setFirstPageUrl(getUrl(1));
        rspVO.setLastPageUrl(getUrl(lastPage));
        if (lastPage > currPage) {
            rspVO.setLastPageUrl(getUrl(currPage + 1));
        }
        rspVO.setPrevPageUrl(getUrl(currPage - 1));
    }

    private String getUrl(Integer page) {
        if (page <= 0) {
            page = 1;
        }
        return "/?page=" + page;
    }

}
